home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-07-31 | 11.7 KB | 442 lines | [TEXT/MMCC] |
- /**************************************************************************
- LGBCheckbox
-
- Public domain, by Zig Zichterman.
-
- This class implements 3D checkboxes according to the guidelines
- suggested in _develop_ 15. Some of the drawing code is taken from
- the public domain source accompanying _develop_ 15.
-
- 07/31/94 zz Draw 3D if 4-bit grey, BW if 4-bit color
- 07/31/94 zz save/restore pen colors
- 1.0b3
- 07/28/94 zz offscreen drawing for less flashy TextBox()
- 1.0b2 (never released)
- 07/20/94 zz call PenNormal() before drawing anything!
- 1.0b1
- **************************************************************************/
- #include "LGBCheckbox.h"
-
- #include <GestaltEqu.h>
-
- #include "LGBControl.h"
- #include "LGBDeviceIterator.h"
- #include "UGBDraw.h"
-
- const short LGBCheckbox_boxWidth = 12;
-
- /**************************************************************************
- Main() [static]
-
- Main entry point for all checkbox calls. Dispatch according to
- message.
- **************************************************************************/
- long
- LGBCheckbox::Main(short inVariation, ControlHandle ioControl,
- short inMsg, long ioParam)
- {
- long returnMe = 0;
-
- // lock the control handle for the duration of this call
- char state = ::HGetState((Handle) ioControl);
- ::HLock((Handle) ioControl);
-
- LGBCheckbox checkbox(*ioControl,(inVariation & useWFont)?true:false);
-
- switch (inMsg) {
- case drawCntl :
- checkbox.Draw(ioParam);
- break;
-
- case testCntl :
- {
- Point hitPt;
- hitPt.h = LoWord(ioParam);
- hitPt.v = HiWord(ioParam);
- if (checkbox.Test(hitPt)) {
- returnMe = inButton;
- }
- }
- break;
-
- case calcCRgns : // only called in 24-bit mode
- { // is 32-bit addressing off?
- long result = 0;
- OSErr err = ::Gestalt(gestaltAddressingModeAttr,&result);
- if (!err && ((result &
- (1L << gestalt32BitAddressing)) == 0)) {
- RgnHandle rgn = (RgnHandle)
- ::StripAddress((Ptr) ioParam);
- checkbox.CalcCRgn(rgn);
- }
- }
- break;
-
- case calcCntlRgn : // only called in 32-bit mode
- checkbox.CalcCRgn((RgnHandle) ioParam);
- break;
- }
-
- // unlock handle
- ::HSetState((Handle) ioControl,state);
- return returnMe;
- }
-
- //—————————————————————————————————————————————————————————————————————————
- // Constructor
- //—————————————————————————————————————————————————————————————————————————
-
- /**************************************************************************
- LGBCheckbox(ControlHandle,Boolean)
-
- construct/initialize a control object. Just stores the control handle
- and the "should I use the window font?" flag in data members.
- **************************************************************************/
- LGBCheckbox::LGBCheckbox(ControlRecord *inControl, Boolean inUseWFont)
- : mControl(inControl), mUseWFont(inUseWFont)
- {
-
- }
-
- //—————————————————————————————————————————————————————————————————————————
- // Dispatch entry points
- //—————————————————————————————————————————————————————————————————————————
-
- /**************************************************************************
- Draw()
-
- Draw the control. inPartCode is a part code specifying which part of
- the control to draw, or 0 for the entire control.
-
- Checkboxes only have inButton, so we ignore the inPartCode.
-
- Save the current drawing environment. Iterate through all the devices
- (screens), drawing the control in color or black and white depending
- on the screen depth. Once done, restore the drawing environment and
- return.
- **************************************************************************/
- void
- LGBCheckbox::Draw(long inPartCode)
- {
- // if we're invisible, don't draw
- if (mControl->contrlVis == false) return;
-
- // save the font
- short font,size,mode,face;
- {
- GrafPtr port;
- ::GetPort(&port);
- font = port->txFont;
- size = port->txSize;
- mode = port->txMode;
- face = port->txFace;
- }
-
- // save the pen colors // will probably crash SEs, so test first
- RGBColor fore,back;
- if (UGBDraw::ColorQDIsPresent()) {
- ::GetForeColor(&fore);
- ::GetBackColor(&back);
- }
-
- // save the clip region
- RgnHandle saveClip = ::NewRgn();
- if (!saveClip) return;
- ::GetClip(saveClip);
-
- // make the pen something sensible
- ::PenNormal();
- ::ForeColor(blackColor);
- ::BackColor(whiteColor);
-
- // loop through all the devices (screens)
- UGBDraw::Offscreen offscreen;
- LGBDeviceIterator device;
- device.Init(mControl->contrlRect);
- short depth = 0;
- do {
- depth = device.Next();
- if (depth == 0) break; // all done with devices
- UGBDraw::OffscreenPre(offscreen);
- if ((depth < 4)
- || (depth == 4 && device.mDeviceIsColor)) {
- DrawBW();
- } else {
- DrawColor();
- }
- UGBDraw::OffscreenPost(offscreen);
- } while(true);
-
- // restore the clip region
- ::SetClip(saveClip);
- ::DisposeRgn(saveClip);
-
- // restore the pen
- if (UGBDraw::ColorQDIsPresent()) {
- ::RGBForeColor(&fore);
- ::RGBBackColor(&back);
- }
-
- // restore the font
- ::TextFont(font);
- ::TextSize(size);
- ::TextMode(mode);
- ::TextFace(face);
- }
-
- /**************************************************************************
- Test()
-
- Return inButton if the point is in our rect
- **************************************************************************/
- Boolean
- LGBCheckbox::Test(Point inHitPt)
- {
- return ::PtInRect(inHitPt,&(mControl->contrlRect));
- }
-
- /**************************************************************************
- CalcCRgn()
-
- Calculate the control's region in the given region handle.
- The region is just our bounding rect.
- **************************************************************************/
- void
- LGBCheckbox::CalcCRgn(RgnHandle ioRgn)
- {
- if (!ioRgn) return; // idiot resistance
- ::RectRgn(ioRgn,&(mControl->contrlRect));
- }
-
- //—————————————————————————————————————————————————————————————————————————
- // Draw
- //—————————————————————————————————————————————————————————————————————————
-
- /**************************************************************************
- DrawBW()
-
- Draw the control in black and white. It is NOT safe to make any
- color QuickDraw calls here.
- **************************************************************************/
- void
- LGBCheckbox::DrawBW(void)
- {
- // Set the pen to black, 1x1
- ::PenNormal();
-
- // set up our font
- if (!mUseWFont) LGBControl::SetupFont();
-
- // calculate box locations
- Rect checkbox,titleBox;
- CalcBoxes(checkbox,titleBox);
-
- // draw the parts
- DrawCheckbox(checkbox);
- DrawTitle(titleBox, mControl->contrlHilite == 255);
- }
-
- /**************************************************************************
- DrawColor()
-
- Draw the control in color
- **************************************************************************/
- void
- LGBCheckbox::DrawColor(void)
- {
- // draw active or inactive?
- if (mControl->contrlHilite == 255) {
- DrawColorInactive();
- } else {
- DrawColorActive();
- }
-
- // restore the pen
- ::PenNormal();
- UGBDraw::PenReallyNormal();
- }
-
- /**************************************************************************
- CalcBoxes()
-
- Figure out where to draw the checkbox and the title.
- **************************************************************************/
- void
- LGBCheckbox::CalcBoxes(Rect &outCheckbox, Rect &outTitleBox)
- {
- const Rect contrlRect = mControl->contrlRect;
- const StringPtr title = mControl->contrlTitle;
- LGBControl::CalcBoxes(contrlRect,title,
- outCheckbox,outTitleBox);
- }
-
- /**************************************************************************
- DrawCheckbox()
-
- Draw the checkbox. Draw the 3D effect, the "X", everything
- but the title and the background.
- **************************************************************************/
- void
- LGBCheckbox::DrawCheckbox(const Rect &inCheckbox,Boolean inColor)
- {
- // draw the frame
- ::FrameRect(&inCheckbox);
-
- // draw the X or erase the guts
- const short value = mControl->contrlValue;
- if (value <= 1) { // erase the insides unless tristated
- Rect eraseMe;
- eraseMe.top = inCheckbox.top + 1;
- eraseMe.left = inCheckbox.left + 1;
- eraseMe.right = inCheckbox.right - 1;
- eraseMe.bottom = inCheckbox.bottom - 1;
- ::EraseRect(&eraseMe);
- }
- if (value == 0) { // clear checkbox
- // do nothing
- } else if (value == 1) { // X
- Rect x;
- x.left = inCheckbox.left;
- x.top = inCheckbox.top;
- x.right = inCheckbox.right - 1;
- x.bottom = inCheckbox.bottom - 1;
- ::MoveTo(x.left,x.top);
- ::LineTo(x.right,x.bottom);
- ::MoveTo(x.left,x.bottom);
- ::LineTo(x.right,x.top);
- } else if (value == 2) { // tristate
- // fabricate a ltGray pattern on the fly. We don't
- // have quickdraw globals and I'm not going to set
- // up A4 to get them.
- unsigned char ltGrey[8];
- ltGrey[0] = ltGrey[2] = ltGrey[4] = ltGrey[6] = 0x88;
- ltGrey[1] = ltGrey[3] = ltGrey[5] = ltGrey[7] = 0x22;
-
- if (inColor) {
- // draw a greyish pattern, not black on white
- UGBDraw::ForeGrey(UGBDraw_grey7);
- UGBDraw::BackGrey(UGBDraw_greyD);
- }
- Rect grayRect = inCheckbox;
- ::InsetRect(&grayRect,1,1);
- ::FillRect(&grayRect,(PatPtr) <Grey);
- if (inColor) {
- UGBDraw::PenNormal();
- }
- }
-
- // draw highlight
- if ((mControl->contrlHilite)
- && (mControl->contrlHilite != 255)) {
- ::PenNormal();
- Rect hilite = inCheckbox;
- ::InsetRect(&hilite,1,1);
- ::FrameRect(&hilite);
- }
- }
-
- /**************************************************************************
- DrawTitle()
-
- Draw the title.
- **************************************************************************/
- void
- LGBCheckbox::DrawTitle(const Rect &inTitleBox, Boolean inDim1Bit)
- {
- const StringPtr title = mControl->contrlTitle;
- ::TextBox(title + 1,*title,&inTitleBox,teFlushDefault);
-
- // grey out the name if inactive
- if (inDim1Bit) {
- unsigned char grey[8];
- grey[0] = grey[2] = grey[4] = grey[6] = 0xAA;
- grey[1] = grey[3] = grey[5] = grey[7] = 0x55;
- ::PenPat((PatPtr) grey);
- ::PenMode(patBic);
- ::PaintRect(&inTitleBox);
- ::PenNormal();
- }
- }
-
- /**************************************************************************
- DrawColorInactive()
-
- Draw the checkbox, in color, but flattened out and inactive
- **************************************************************************/
- void
- LGBCheckbox::DrawColorInactive(void)
- {
- // Set the pen to black, 1x1
- ::PenNormal();
-
- // set up our font
- if (!mUseWFont) LGBControl::SetupFont();
-
- // calculate box locations
- Rect checkbox,titleBox;
- CalcBoxes(checkbox,titleBox);
-
- // grey out our entire background
- UGBDraw::Background();
- ::EraseRect(&(mControl->contrlRect));
-
- // set the pen to the "inactive control" color
- // set the backcolor to white
- UGBDraw::PenFrameInactive();
- UGBDraw::BackGrey(UGBDraw_greyF);
- DrawCheckbox(checkbox,true);
-
- // draw the button title
- // set the background to grey
- UGBDraw::Background();
- DrawTitle(titleBox);
- }
-
- /**************************************************************************
- DrawColorActive()
-
- Draw the checkbox, in 3D color
- **************************************************************************/
- void
- LGBCheckbox::DrawColorActive(void)
- {
- // Set the pen to black, 1x1
- ::PenNormal();
-
-
- // set up our font
- if (!mUseWFont) LGBControl::SetupFont();
-
- // calculate box locations
- Rect checkbox,titleBox;
- CalcBoxes(checkbox,titleBox);
-
- // grey out our entire background
- UGBDraw::Background();
- ::EraseRect(&(mControl->contrlRect));
-
- // set the pen to the "active control" color
- // set the backcolor to white
- UGBDraw::PenFrameActive();
- UGBDraw::BackGrey(UGBDraw_greyF);
- DrawCheckbox(checkbox,true);
-
- // draw the button title
- // set the background to grey
- UGBDraw::Background();
- DrawTitle(titleBox, mControl->contrlHilite == 255);
-
- // draw 3D effect around checkbox
- // top left sides
- UGBDraw::ForeGrey(UGBDraw_greyA);
- ::MoveTo(checkbox.left - 1,checkbox.bottom);
- ::LineTo(checkbox.left - 1,checkbox.top - 1);
- ::LineTo(checkbox.right,checkbox.top - 1);
-
- // bottom right sides
- UGBDraw::ForeGrey(UGBDraw_greyF);
- ::MoveTo(checkbox.left,checkbox.bottom);
- ::LineTo(checkbox.right,checkbox.bottom);
- ::LineTo(checkbox.right,checkbox.top);
- }
-